/**

This file is part of MaCI/GIMnet.

MaCI/GIMnet is free software: you can redistribute it and/or modify it 
under the terms of the GNU Lesser General Public License as published 
by the Free Software Foundation, either version 3 of the License, or 
(at your option) any later version.

MaCI/GIMnet is distributed in the hope that it will be useful, but WITHOUT 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public 
License for more details.

You should have received a copy of the GNU Lesser General Public 
License along with GIMnet. (See COPYING.LESSER) If not, see 
<http://www.gnu.org/licenses/>.

**/
/**
 * \file
 * \brief MaCI - Dummy Interface Client header
 * \author Matthieu Myrsky <matthieu.myrsky@tkk.fi>
 *
 * $Id: EmergencyStopClient.hpp,v 1.4 2009-12-08 10:48:28 morsko Exp $
 *
 */
#ifndef _MACI_INTERFACE_EMERGENCYSTOPCLIENT_HPP_
#define _MACI_INTERFACE_EMERGENCYSTOPCLIENT_HPP_

#include "MaCI.hpp"
#include "thread.hpp"
#include "sync.hpp"

// These are not necessarily required here, but defined to make the
// interface easier to include.
#include "EmergencyStopData.hpp"

// Forward declare gimi::GIMI
namespace gimi {
  class GIMI;
}

namespace MaCI {
  namespace EmergencyStop {
    
    // Forward declaration.
    class CEmergencyStopData;
    class CEmergencyStopClient;

    
    /** Callback interface class for EmergencyStop interface.
     *
     * This interface defines functions which can be used for
     * EmergencyStopClient callbacks. These functions are executed (more
     * detail per function basis) as new data arrives, and directly
     * from the context of the receiving thread. <b>Therefore, it is
     * important that the handling function is as simple and fast as
     * possible, as it will block the execution of the receiving
     * thread while executed.</b>
     */
    class CEmergencyStopClientCallback
    {
    public:
      
      CEmergencyStopClientCallback() {}
      virtual ~CEmergencyStopClientCallback() {}


      /** Handler function for EmergencyStopData event.
       *
       * This function is called when the EmergencyStopClient receives new
       * data from the server.
       *
       * \note <b>Keep this function simple & fast as it will block the 
       * data receiving thread while executing!</b>
       *
       * @param[in] aData       Constant reference to CEmergencyStopData element 
       *                        containing the received event.
       * @param[in] aDataSequence Sequence number of the received data. 
       *                        This should increment by one on each call.
       * @param[in] aEmergencyStopClient Reference to EmergencyStopClient 
       *                        instance which received this event.
       */
      virtual void OnEmergencyStopDataEvent(const CEmergencyStopData &aData, 
                                            const unsigned int aDataSequence,
                                            CEmergencyStopClient &aEmergencyStopClient) = 0;
    };


    /** MaCI - EmergencyStop Client interface.
     * 
     * This class contains the methods and types for using
     * a MaCI::EmergencyStop service in the GIMnet.
     */
    class CEmergencyStopClient 
      : private gim::CSync,
        private gim::CThread,
        public MaCI::CMaCI
    {
    public:
      /** Constructor.
       * 
       * Constructor of the EmergencyStopClient. This requires;
       * a pointer to Initialized and connected GIMI, minor
       * number of this interface (Used as GIMI minor number)
       *
       * @param[in] aGIMIPtr Pointer to GIMI used for communication
       * @param[in] aInterfaceMinor Interface minor number. Usually
       *            used to indicate the instance of devices of same
       *            type. Can be left out if MaCISL is used.
       */     
      CEmergencyStopClient(gimi::GIMI *aGIMIPtr, const int aInterfaceMinor = -1);

      
      /** Destructor.
       */
      ~CEmergencyStopClient();


      /** Receive EmergencyStop status Event.
       *
       * @param[out] aData     Reference to CEmergencyStopData to copy the data to.
       * @param aSequence      Pointer to sequence number. If this is NULL,
       *                       the most recent position is returned immediately.
       *                       If this is not NULL, the value pointed
       *                       should be set to 0 on the first call to this function.
       *                       After each call, the sequence number of the returned
       *                       data is stored here. If user wants to read all the
       *                       measures available, the value pointed should not be
       *                       modified after the first call.
       * @param[in] aTimeout_ms Timeout value. If the operation is not completed
       *                       before timeout is reached, the operation fails.
       * @return               true - Operation was succesfull, new data is copied
       *                       to provided location.
       *                       false - Operation failed; timeout or generic error
       *                       encountered.
       */
      bool GetEmergencyStopStatusEvent(CEmergencyStopData &aData,
                                       unsigned int *aSequence,
                                       const unsigned int aTimeout_ms);
      
      /** Activates client
       * 
       * Activate the client. When client is activated, it will start sending 
       * watchdog messages to server. Also it's added to be monitored by server. 
       * If watchdog message is missing, server will automatically create an
       * emergency stop. Remember always call DeactivateClient-function when 
       * exiting the client, otherwise an emergency stop will be occured.
       *
       * @param[in] aTimeout_ms   Timeout value to wait response from server if 
       *                          client is succesfully activated.
       * @return                  True, if client is succesfully activated. 
       *                          False, if no response from server.
       */
      bool ActivateClient(unsigned int aTimeout_ms);

      /** Deactivate client 
       *
       * Deactivate client. Client will stop sending watchdog messages. It will 
       * be also removed from servers client monitor list, and no emergency stop
       * messages will be created. 
       *
       * @param[in] aTimeout_ms   Timeout value to wait response from server if 
       *                          client is succesfully deactivated.
       * @return                  True, if client is succesfully activated. 
       *                          False, if no response from server.
       */
      bool DeactivateClient(unsigned int aTimeout_ms);
          
      /** Activate emeregency stop
       *
       * Activates the emergency stop. 
       *
       * @param[in] aTimeout_ms   Timeout value to wait response from server if 
       *                          emergency stop is succesfully activated.
       * @return                  True, if client is succesfully activated. 
       *                          False, if no response from server.
       */
      bool ActivateEmergencyStop(unsigned int aTimeout_ms);  

      /** Deactivate emeregency stop
       *
       * Deactivates the emergency stop. 
       *
       * @param[in] aTimeout_ms   Timeout value to wait response from server if 
       *                          emergency stop is succesfully deactivated.
       * @return                  True, if client is succesfully deactivated. 
       *                          False, if no response from server.
       */
      bool DeactivateEmergencyStop(unsigned int aTimeout_ms);

      /** Assigns the EmergencyStop client callback function. 
       *
       * This sets a function object for calling a position client
       * callback. If this is set, the interface calls the assigned
       * functions immediately when event is available.
       * 
       * \note As the function is run in the context of the receiving
       * thread, user must make sure that the callback function is
       * fast. As if the function executes too long, receiving events
       * is interrupted.
       *
       * @param[in] aEmergencyStopClientCallback Pointer to class implementing the interface
       *                                 CEmergencyStopClientCallback.
       */
      void SetEmergencyStopClientCallback(CEmergencyStopClientCallback *aEmergencyStopClientCallback) {
        iEmergencyStopClientCallback = aEmergencyStopClientCallback;
      }

    protected:

      /** Open client interface.
       *
       * Implementation of Open() for the class. This function is
       * called by the base class CMaCI::Open() function.
       */
      EMaCIError DoOpen(void);
      
      
      /** Close client interface.
       *
       * Implementation of Close() for the class. This function is
       * called by the base class CMaCI::Close() function.
       */
      EMaCIError DoClose(void);


    private:
      /// Thread runner function. Is in charge of receiving events.
      int ThreadFunction(const int aThreadNumber);
      int ProcessMessage(const gimi::GIMIMessage &msg);

      //data.
      unsigned int iServerTimeoutTime;
      bool iWatchdogThreadActive;
      unsigned int iEmergencyStopDataSequence; ///< Received data sequence
      CEmergencyStopData iLastEmergencyStopData; ///< Last element available
      CEmergencyStopClientCallback *iEmergencyStopClientCallback; ///< Pointer to class instance containing callback functions.

      // Override copy & assignment operator privately to disable class copying.
      CEmergencyStopClient(const CEmergencyStopClient &)
        : CSync(1,1),
          CThread(2),
          CMaCI(NULL,0,0,""),
          iServerTimeoutTime(10000000),
          iWatchdogThreadActive(false),
          iEmergencyStopDataSequence(-1),
          iLastEmergencyStopData(),
          iEmergencyStopClientCallback(NULL) {}
      CEmergencyStopClient &operator=(const CEmergencyStopClient &) { return *this; }
    };


  }
}

#endif //_MACI_INTERFACE_EMERGENCYSTOPCLIENT_HPP_
